to get this notebook working:

poetry add ipykernel hvplot shapely searvey geoviews utide
In [8]:
import searvey
import shapely
import utide
import pandas as pd
import hvplot.pandas
In [9]:
# small function to detide signal (using Utide: https://github.com/wesleybowman/UTide)
def surge(ts: pd.Series, lat: float, resample: int = None): 
    ts0 = ts.copy()
    OPTS = {
        "constit": "auto", 
        "method": "ols", 
        "order_constit": "frequency",
        "Rayleigh_min": 0.97,
        "lat": lat,
        "verbose": True
    }
    if resample is not None:
        ts = ts.resample(f"{resample}min").mean()
        ts = ts.shift(freq=f"{resample / 2}min")
        coef = utide.solve(ts.index, ts, **OPTS)
        tidal = utide.reconstruct(ts0.index, coef, verbose = OPTS["verbose"])
        return pd.Series(data=ts0.values - tidal.h, index = ts0.index)
In [ ]:
ioc_df = searvey.get_ioc_stations()
africa = shapely.box(-26, -35, 63, 38)
ioc_africa = ioc_df[ioc_df.geometry.within(africa)]
ioc_africa.hvplot(tiles=True, hover_cols = ['ioc_code'])
Out[ ]:

example for zanz:

In [12]:
station = "zanz"
sensor = "prs"
In [11]:
raw = searvey.fetch_ioc_station(
    station, 
    pd.Timestamp.now()-pd.Timedelta(days = 365), 
    pd.Timestamp.now()
)
raw.describe()
Out[11]:
bat enc prs rad sw1 sw2
time
2024-05-06 17:13:00 0.0123 1.923 1.858 3.001 0.06 0.06
2024-05-06 17:14:00 NaN NaN 1.850 NaN NaN NaN
2024-05-06 17:15:00 NaN NaN 1.840 NaN NaN NaN
2024-05-06 17:16:00 NaN NaN 1.829 2.975 NaN NaN
2024-05-06 17:17:00 NaN NaN 1.828 NaN NaN NaN
... ... ... ... ... ... ...
2025-05-06 14:54:00 NaN NaN 2.712 NaN NaN NaN
2025-05-06 14:55:00 NaN NaN 2.709 -0.302 NaN NaN
2025-05-06 14:56:00 NaN NaN 2.712 NaN NaN NaN
2025-05-06 14:57:00 NaN NaN 2.710 NaN NaN NaN
2025-05-06 14:58:00 0.0124 2.706 2.709 -0.301 0.06 0.06

513456 rows × 6 columns

In [18]:
_lat = ioc_df[ioc_df.ioc_code == station].lat.values[0]
In [19]:
detided = surge(raw[sensor], lat = _lat, resample=2)
solve: matrix prep ... solution ... done.
prep/calcs ... done.

visualise the raw signal

In [29]:
raw[sensor].sample(frac=1/5).dropna().hvplot().opts(width=1300, height = 900)
Out[29]:

visualise the detided signal (without tidal components)

In [30]:
detided.sample(frac=1/5).hvplot(ylim = (-0.5, 0.5)).opts(width=1300, height = 900)
Out[30]: